﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SevenZip;
using Xceed.FileSystem;

namespace picomp
{
    internal class ZipReader
    {
        public ZipReader(string filename)
        {
            Filename = filename;
        }

        public string Filename { get; private set; }

        private static bool IsImageFile(string file)
        {
            var extensions = new[] {".jpg", ".jpeg", ".bmp", ".png"};
            var fileExt = Path.GetExtension(file).ToLowerInvariant();
            return extensions.Any(extension => String.CompareOrdinal(fileExt, extension) == 0);
        }

        public int CountImageFiles()
        {
            try
            {
                var extractor = new SevenZipExtractor(Filename);
                return (extractor.ArchiveFileNames.Where(IsImageFile)).Count();
            }
            catch (SevenZipArchiveException exc)
            {
                Console.WriteLine(exc.Message);
                return 0;
            }
        }

        public IEnumerable<Stream> ImageFiles()
        {
            List<string> files = null;
            SevenZipExtractor extractor = null;
            var archiveOk = true;
            try
            {
                extractor = new SevenZipExtractor(Filename);
                files = (from p in extractor.ArchiveFileNames
                         where IsImageFile(p)
                         orderby p
                         select p).ToList();
            }
            catch (SevenZipArchiveException exc)
            {
                archiveOk = false;
                Console.WriteLine(exc.Message);
            }

            if (archiveOk)
            {
                foreach (var fname in files)
                {
                    using (var ms = new MemoryStream())
                    {
                        Stream shrunk;
                        try
                        {
                            extractor.ExtractFile(fname, ms);
                            var resizer = new PicResizer();
                            shrunk = resizer.ResizeImage(ms);
                        }
                        catch (Exception exc)
                        {
                            shrunk = null;
                            Console.WriteLine(exc);
                        }

                        yield return shrunk;
                    }
                }
            }

            if (extractor != null) extractor.Dispose();
        }

        private static bool IsValidOtherFile(string file)
        {
            var blockedExts = new[]
                              {
                                  ".txt", ".db",
                                  ".url", ".lnk",
                                  ".psd"
                              };
            var fileExt = Path.GetExtension(file);
            return !string.IsNullOrEmpty(fileExt) && !IsImageFile(file) &&
                   blockedExts.All(x => String.Compare(fileExt, x, StringComparison.OrdinalIgnoreCase) != 0);
        }

        public IEnumerable<DiskFile> OtherFiles(string coll_id)
        {
            using (var extractor = new SevenZipExtractor(Filename))
            {
                var files = (from p in extractor.ArchiveFileNames
                             where IsValidOtherFile(p)
                             orderby p
                             select p).ToList();
                var counter = 1;
                foreach (var fname in files)
                {
                    var tmpname = Utilities.GetTempFilePath(Path.GetTempPath(),
                                                            string.Format("vid_{0}_{1:d3}_", coll_id, counter++),
                                                            Path.GetExtension(fname));
                    var diskFile = new DiskFile(tmpname);

                    try
                    {
                        using (var stream = diskFile.CreateWrite())
                        {
                            extractor.ExtractFile(fname, stream);
                        }
                    }
                    catch (Exception exc)
                    {
                        diskFile.Delete();
                        diskFile = null;
                        Console.WriteLine(exc);
                    }
                    yield return diskFile;
                }
            }
        }
    }
}